home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Utilities / DlogUtil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  39.1 KB  |  1,501 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DlogUtil.cpp
  3.  
  4.     Contains:    implementation of dialog utility functions
  5.  
  6.     Owned by:    Tantek Çelik
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <10>     7/10/96    RA        1363236: Cosemtic Document/PartInfo dlg
  13.                                     fixes
  14.          <9>     6/27/96    jpa        1361886: Added LookupString
  15.          <8>     6/22/96    EL        1344140: make sure OK button can be
  16.                                     disabled. 1210509 make sure ShowAlert can
  17.                                     be called from Pref.
  18.          <7>      6/6/96    EL        1293250: SetDialogTextStyle should
  19.                                     recalculate line height and font height.
  20.                                     Code from Jon.
  21.          <6>      5/1/96    JA        1213332: Force 68k alignment of FontSpec
  22.                                     resource type.
  23.          <5>    .04.1996    NP        Comment about not checking for being in the
  24.                                     background before posing alert.
  25.          <4>      1/5/96    eeh        1298401: don't disable keyboard changes
  26.          <3>      1/4/96    eeh        fix header
  27.          <2>      1/4/96    eeh        1226961: make ActivateAllControls
  28.                                     non-static
  29.  
  30.     To Do:
  31.     In Progress:
  32.         
  33. */
  34.  
  35. #ifndef _EXCEPT_
  36. #include <Except.h>
  37. #endif
  38.  
  39. #ifndef SOM_Module_OpenDoc_Errors_defined
  40. #include <ErrorDef.xh>
  41. #endif
  42.  
  43. #ifndef _DLOGUTIL_
  44. #include <DlogUtil.h>
  45. #endif
  46.  
  47. #ifndef _PLFMDEF_
  48. #include <PlfmDef.h>
  49. #endif
  50.  
  51. #ifndef _ODUTILS_
  52. #include <ODUtils.h>
  53. #endif
  54.  
  55. #ifndef SOM_ODMenuBar_xh
  56. #include <MenuBar.xh>
  57. #endif
  58.  
  59. #ifndef SOM_ODDispatcher_xh
  60. #include <Disptch.xh>
  61. #endif
  62.  
  63. #ifndef SOM_ODSession_xh
  64. #include <ODSessn.xh>
  65. #endif
  66.  
  67. #ifndef SOM_ODWindowState_xh
  68. #include <WinStat.xh>
  69. #endif
  70.  
  71. #ifndef SOM_ODClipboard_xh
  72. #include <Clipbd.xh>
  73. #endif
  74.  
  75. #ifndef _ODMEMORY_
  76. #include <ODMemory.h>
  77. #endif
  78.  
  79. #ifndef __GESTALTEQU__
  80. #include <GestaltEqu.h>
  81. #endif
  82.  
  83. #ifndef __TOOLUTILS__
  84. #include <ToolUtils.h>
  85. #endif
  86.  
  87. #ifndef _PASCLSTR_
  88. #include <PasclStr.h>
  89. #endif
  90.  
  91. #ifndef __DIALOGS__
  92. #include <Dialogs.h>
  93. #endif
  94.  
  95. #ifndef __TEXTEDIT__
  96. #include <TextEdit.h>
  97. #endif
  98.  
  99. #ifndef __PALETTES__
  100. #include <Palettes.h>
  101. #endif
  102.  
  103. #ifndef _MEMMGR_
  104. #include <MemMgr.h>
  105. #endif
  106.  
  107. #ifndef _ODDEBUG_
  108. #include <ODDebug.h>
  109. #endif
  110.  
  111. #ifndef _USERSRCM_
  112. #include <UseRsrcM.h>
  113. #endif
  114.  
  115. #ifndef SOM_ODNameSpaceManager_xh
  116. #include <NmSpcMg.xh>
  117. #endif
  118.  
  119. #ifndef SOM_Module_OpenDoc_Commands_defined
  120. #include <CmdDefs.xh>
  121. #endif
  122.  
  123. #ifndef SOM_ODStorageSystem_xh
  124. #include <ODStor.xh>
  125. #endif
  126.  
  127. #ifndef SOM_ODPlatformTypeList_xh
  128. #include <PfTypLs.xh>
  129. #endif
  130.  
  131. #ifndef _TEMPOBJ_
  132. #include "TempObj.h"
  133. #endif
  134.  
  135. // Types
  136. struct _MenuItemInfo
  137. {
  138.     MenuHandle    menu;
  139.     short        item;
  140.     Str255        text;
  141.     short        cmdChar;
  142.     short        iconID;
  143.     short        markChar;
  144.     Style        textStyle;
  145. };
  146. typedef struct _MenuItemInfo MenuItemInfo;
  147.  
  148. struct _DialogBoxInfo
  149. {
  150.     MenuItemInfo    redo;
  151.     // Can put other things in here later on
  152.     // like supporting movable modals, etc.
  153. };
  154. typedef struct _DialogBoxInfo DialogBoxInfo;
  155.  
  156. // Key codes
  157. // const char kEscapeKey        = 0x1B;
  158. // const char kUpArrowKey        = 0x1E;
  159. // const char kDownArrowKey    = 0x1F;
  160. const char kPageUpKey        = 0x0B;
  161. const char kPageDownKey        = 0x0C;
  162. const char kHomeKey            = 0x01;
  163. const char kEndKey            = 0x04;
  164.  
  165. // Control settings
  166. const short kControlInactive = 255;
  167. const short kControlActive = 0;
  168.  
  169. // Dialog item assumptions
  170. const short kOKButton = 1;
  171. const short kCancelButton = 2;
  172.  
  173. // Memory requirements
  174. const size_t kODMinFreeSpaceToShowDialog = 4 * 1024;
  175.     
  176. static Environment        *sEv;
  177. static ODSession        *sSession;
  178. static ModalFilterUPP    sFilter = kODNULL;
  179. static ModalFilterUPP    sButtonKeyFilter = kODNULL;
  180. static ModalFilterUPP    sArrowKeyFilter = kODNULL;
  181. static UserItemUPP        sOutlineDrawProc = kODNULL;
  182. static short            sCmdKeyStrResID = 0;    
  183. static DialogScriptData*
  184.                         sDlogScriptData = kODNULL;    
  185.     // Res ID of STR# that contains cmd-keys for buttons
  186.  
  187. static DialogBoxInfo* sDialogInfo = kODNULL;
  188.  
  189. // Private functions
  190. static void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem );
  191. static void RestoreMenuItem( MenuItemInfo *savedItem );
  192.  
  193.  
  194. //==============================================================================
  195. // Preflighting Dialogs and Alerts
  196. //==============================================================================
  197.  
  198. //------------------------------------------------------------------------------
  199. // Centering
  200. //------------------------------------------------------------------------------
  201.  
  202. static ODBoolean
  203. GetFrontWindowBounds( Rect &bounds )
  204. {
  205.     WindowPtr wp;
  206.     {
  207.         TempODWindow win = sSession->GetWindowState(sEv)->AcquireActiveWindow(sEv);
  208.         wp = win ? win->GetPlatformWindow(sEv) : FrontWindow();
  209.     }
  210.     
  211.     if( wp ) {
  212.         bounds = wp->portRect;
  213.         Rect *mapBounds;
  214.         if( wp->portBits.rowBytes & 0xC000 )            // Color port
  215.             mapBounds= &(**((CGrafPtr)wp)->portPixMap).bounds;
  216.         else
  217.             mapBounds= &wp->portBits.bounds;
  218.         OffsetRect(&bounds,-mapBounds->left,-mapBounds->top);
  219.         return kODTrue;
  220.     } else {
  221.         bounds = ODQDGlobals.screenBits.bounds;        // No win, use main screen
  222.         bounds.top += GetMBarHeight();
  223.         return kODFalse;
  224.     }
  225. }
  226.  
  227.  
  228. static void
  229. GetWindowsMainScreen( const Rect &windowBounds, Rect &screenBounds )
  230. {
  231.     long area=0;
  232.     
  233.     GDHandle gdh;
  234.     Rect devBounds,sectBounds;
  235.     long maxArea=0;
  236.     
  237.     for( gdh = GetDeviceList(); gdh; gdh = GetNextDevice(gdh) ) {
  238.         devBounds = (**gdh).gdRect;
  239.         if( gdh == GetMainDevice() )
  240.             devBounds.top += GetMBarHeight();
  241.         if( SectRect(&devBounds,&windowBounds,§Bounds) ) {
  242.             area = (sectBounds.right-sectBounds.left) * (long)(sectBounds.bottom-sectBounds.top);
  243.             if( area > maxArea ) {
  244.                 maxArea = area;                    // Best screen so far
  245.                 screenBounds = devBounds;
  246.                 if( gdh==GetMainDevice() )
  247.                     screenBounds.right -= 30;    // Leave room for Finder disk icons
  248.             }
  249.         }
  250.     }
  251.     if( area==0 ) {
  252.         screenBounds = ODQDGlobals.screenBits.bounds;        // Default: use main screen
  253.         screenBounds.top += GetMBarHeight();
  254.     }
  255. }
  256.  
  257.  
  258. static void
  259. CenterDialog( short ¢erFlag, Rect &bounds )
  260. {
  261.     /* Do centering manually. Why? Even though the Dialog Manager handles
  262.        automatic centering, it calls FrontWindow to find the parent window.
  263.        This will return an incorrect window (a floater) if there are floating
  264.        windows. We have to reproduce the centering effect but using the
  265.        actual frontmost non-floating window. */
  266.     const short noAutoCenter                    = 0x0000;
  267.     const short centerParentWindowScreen        = 0x680A;        // From Types.r
  268.     const short alertPositionParentWindowScreen = 0x700A;
  269.     const short centerParentWindow                = 0xA80A;
  270.     const short alertPositionParentWindow        = 0xB00A;
  271.     // We don't do anything for other flags.
  272.     
  273.     if( (centerFlag != centerParentWindowScreen) &&  (centerFlag != alertPositionParentWindowScreen)
  274.         && (centerFlag != centerParentWindow) &&  (centerFlag != alertPositionParentWindow) )
  275.         return;
  276.     
  277.     Rect centerBounds;
  278.     if( GetFrontWindowBounds(centerBounds)
  279.             && (centerFlag==centerParentWindowScreen ||
  280.                 centerFlag==alertPositionParentWindowScreen) ) {
  281.         Rect screenBounds;
  282.         GetWindowsMainScreen(centerBounds,screenBounds);
  283.         centerBounds = screenBounds;
  284.     }
  285.     
  286.     Point pos;
  287.     pos.h = ((centerBounds.right-centerBounds.left)-(bounds.right-bounds.left)) >>1;
  288.     pos.v = ((centerBounds.bottom-centerBounds.top)-(bounds.bottom-bounds.top));
  289.     if( centerFlag==centerParentWindowScreen || centerFlag==centerParentWindow )
  290.         pos.v /= 2;
  291.     else if( centerFlag==alertPositionParentWindowScreen || centerFlag==alertPositionParentWindow )
  292.         pos.v /= 3;
  293.         
  294.     pos.h += centerBounds.left;
  295.     pos.v += centerBounds.top;
  296.     OffsetRect(&bounds, pos.h-bounds.left, pos.v-bounds.top);
  297.     centerFlag = noAutoCenter;            // It's already centered now
  298. }
  299.  
  300.  
  301. //------------------------------------------------------------------------------
  302. // PreflightDialog
  303. //------------------------------------------------------------------------------
  304.  
  305. static Handle
  306. PreflightDialog( ODBoolean isDLOG, short id )
  307. {
  308.     Handle rsrc;
  309.     ODBoolean ok;
  310.     
  311.     if( isDLOG ) {
  312.         // Load DLOG and DITL:
  313.         rsrc = Get1Resource('DLOG', id);
  314.         DialogTemplate** dlogTemplate = (DialogTemplate**)rsrc;
  315.         ok = dlogTemplate && Get1Resource('DITL', (*dlogTemplate)->itemsID);
  316.         if( ok ) {
  317.             // Get the centering flag & adjust dialog centering:
  318.             HLock(rsrc);
  319.             size_t centerFlag = (size_t) &(**dlogTemplate).title;
  320.             centerFlag += *(unsigned char*)centerFlag +1;    // skip title
  321.             centerFlag += (centerFlag & 1);                    // word align
  322.             CenterDialog(*(short*)centerFlag, (**dlogTemplate).boundsRect);
  323.             HUnlock(rsrc);
  324.         }
  325.     } else {
  326.         // Load ALRT and DITL:
  327.         rsrc = Get1Resource('ALRT', id);
  328.         AlertTemplate** alrtTemplate = (AlertTemplate**)rsrc;
  329.         ok = alrtTemplate && Get1Resource('DITL', (*alrtTemplate)->itemsID);
  330.         if( ok ) {
  331.             // Get the centering flag & adjust alert centering:
  332.             HLock(rsrc);
  333.             short *centerFlag = (short*)( (size_t)*alrtTemplate + sizeof(AlertTemplate) );
  334.             CenterDialog(*centerFlag,(**alrtTemplate).boundsRect);
  335.             HUnlock(rsrc);
  336.         }
  337.     }
  338.     
  339.     if( !ok ) {
  340. #if ODDebug
  341.         OSErr err = ResError();
  342.         WARN("Could not load dialog/alert %hd: error %hd",id,err);
  343. #endif
  344.         SysBeep(2);                            // At least give some indication
  345.         rsrc = kODNULL;
  346.     } else {
  347.         // Bail if space is really, really low. Don't even beep, this might cause
  348.         // a large 'snd' to be loaded.
  349.         if( !ODHaveFreeSpace(kODMinFreeSpaceToShowDialog,kODMinFreeSpaceToShowDialog,
  350.                              kODTrue) ) {
  351.             WARN("Whoa, not enough memory to show a dialog/alert!");
  352.             ReleaseResource(rsrc);
  353.             rsrc = kODNULL;
  354.         }
  355.     }
  356.     
  357.     return rsrc;
  358. }
  359.  
  360.  
  361. //==============================================================================
  362. // Displaying Dialogs and Alerts
  363. //==============================================================================
  364.  
  365. DialogPtr
  366. ODGetNewDialog( Environment *ev, short resID, ODSession *session, ODBoolean defaultButtons )
  367. {
  368.     ASSERT(session!=kODNULL, kODErrIllegalNullInput);
  369.  
  370.     sEv = ev ?ev :somGetGlobalEnvironment();
  371.     sSession = session;
  372.  
  373.     Handle dlogRsrc = PreflightDialog(kODTrue,resID);
  374.     if( ! dlogRsrc )
  375.         return kODNULL;
  376.  
  377.     DialogPtr dlog = ::GetNewDialog(resID,kODNULL,(WindowPtr)-1L);
  378.     if( dlog ) {
  379.         if( defaultButtons ) {
  380.             ::SetDialogDefaultItem(dlog,kStdOkItemIndex);
  381.             ::SetDialogCancelItem(dlog,kStdCancelItemIndex);
  382.         }
  383.         ::SetDialogTracksCursor(dlog,kODTrue);
  384.         
  385.         sCmdKeyStrResID = 0;    // Don't use command-key lookup unless told to
  386.         
  387.         InitCursor();            // Show arrow
  388.     }
  389.     
  390.     ReleaseResource(dlogRsrc);
  391.     
  392.     return dlog;
  393. }
  394.  
  395. ODSShort
  396. ShowAlert(Environment *ev, ODSShort alertID, ModalFilterUPP modalFilter, ODSession *session)
  397. {
  398.     ASSERT(session != kODNULL, kODErrIllegalNullInput);
  399.  
  400.     CUsingLibraryResources r;
  401.  
  402.     SetCursor(&(ODQDGlobals.arrow));
  403.  
  404.     sEv = ev ?ev :somGetGlobalEnvironment();
  405.     sSession = session;
  406.  
  407.     Handle alrtRsrc = PreflightDialog(kODFalse,alertID);
  408.     if( ! alrtRsrc )
  409.         return cancel;
  410.     
  411.     // Success at last!
  412.  
  413.     // THIS ALERT SHOULD PROBABLY BE PROTECTED WITH A CHECK FOR THE APP
  414.     //    BEING IN THE BACKGROUND
  415.     short alertReturn = Alert(alertID, modalFilter);
  416.     
  417.     ReleaseResource(alrtRsrc);
  418.  
  419.     return alertReturn;
  420. }
  421.  
  422. pascal Boolean
  423. ODDialogFilterProc( DialogPtr dp, EventRecord *event, short *item )
  424. {
  425.     ODBoolean dispatch = kODFalse;
  426.     
  427.     if( event->what==updateEvt || event->what==activateEvt ) {
  428.         if( (WindowPtr)event->message != dp )    // Dispatch updates/activates of other windows
  429.             dispatch = kODTrue;
  430.             
  431.     } else if( event->what==nullEvent || event->what==osEvt )    // Ditto null/suspend/resume
  432.         dispatch = kODTrue;
  433.     
  434.     else if( event->what==mouseDown ) {
  435.         WindowPtr wp;
  436.         if( ::FindWindow(event->where,&wp)==inDrag && wp==dp ) {    // Dragging me!
  437.             Rect bounds = ODQDGlobals.screenBits.bounds;
  438.             DragWindow(dp,event->where,&bounds);
  439.             event->what = nullEvent;
  440.         }
  441.         
  442.     } else if( event->what==keyDown ) {
  443.         // Cmd-A means select all if there is editable text:
  444.         short curTextItem = ((DialogPeek)dp)->editField + 1;
  445.         char key = event->message & charCodeMask;
  446.         if( curTextItem>0 && (key=='a' || key=='A') && (event->modifiers & cmdKey) )
  447.             SelectDialogItemText(dp, curTextItem, 0, 32767);
  448. #ifdef TO_BE_DELETED
  449.         else
  450.         {
  451.             long scriptNum = GetScriptManagerVariable( smKeyScript );
  452.             long curScript = FontToScript(dp->txFont);
  453.             if ( curScript != scriptNum )
  454.             {
  455. //                DebugStr( "\pChanging system font;g" );
  456.                 short myFont = GetScriptVariable( scriptNum, smScriptAppFond );
  457.                 WindowPtr savePort;
  458.                 GetPort(&savePort);
  459.                 SetPort(dp);
  460.                 TextFont( myFont );
  461.                 SetPort(savePort);
  462.             }
  463.         }
  464. #endif /* TO_BE_DELETED */
  465.     }
  466.     
  467.     if( dispatch ) {
  468.         TRY{
  469.             ODDispatcher* dispatcher = sSession->GetDispatcher(sEv);
  470.             if (dispatcher)
  471.                 dispatcher->Dispatch(sEv, (ODEventData*)event);
  472.         }CATCH_ALL{
  473.         }ENDTRY
  474.     }
  475.     
  476.     // Forward other events to the standard filter-proc:    
  477.     ModalFilterUPP proc;
  478.     OSErr err= GetStdFilterProc(&proc);
  479.     if( err==noErr )
  480.         return CallModalFilterProc(proc, dp,event,item);    // Call through to std filter-proc
  481.     else {
  482.         WARN("Couldn't get std filter proc!");
  483.         return false;
  484.     }
  485. }
  486.  
  487.  
  488. ModalFilterUPP
  489. GetODDialogFilter( )
  490. {
  491.     if( !sFilter )
  492.         sFilter = NewModalFilterProc(&ODDialogFilterProc);
  493.     return sFilter;
  494. }
  495.  
  496.  
  497. //==============================================================================
  498. // Filter Procs & Such
  499. //==============================================================================
  500.  
  501. static void
  502. ActivateControl(DialogPtr dialog, short item, Boolean isActivate)
  503. {
  504.     short            itemType;
  505.     Rect            itemRect;
  506.     ControlHandle    cntrlHandle;
  507.  
  508.     GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  509.     ASSERT_CONTROL_ITEM(itemType);
  510.     
  511.     CUsingLibraryResources r;
  512.  
  513.     if ( isActivate )
  514.     {
  515.         HiliteControl(cntrlHandle, GetControlReference(cntrlHandle));
  516.     }
  517.     else
  518.     {
  519.         SetControlReference(cntrlHandle, (**cntrlHandle).contrlHilite);
  520.         HiliteControl(cntrlHandle, kControlInactive);
  521.     }
  522. }
  523.  
  524. void
  525. ActivateAllControls(DialogPtr dialog, Boolean isActivate)
  526. {
  527.     short            itemType;
  528.     Rect            itemRect;
  529.     ControlHandle    cntrlHandle;
  530.     short            item;
  531.  
  532.     for (item = 1; item <= CountDITL(dialog); ++item)
  533.     {
  534.         GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  535.         itemType &= ~kItemDisableBit;
  536.         if ( itemType>=ctrlItem && itemType<=ctrlItem+resCtrl )
  537.             ActivateControl(dialog, item, isActivate);
  538.     }
  539. }
  540.  
  541.  
  542. pascal Boolean ODArrowKeyFilterProc( DialogPtr dlg, ODEventData* event,
  543.         short* itemHit )
  544. {
  545.     Boolean result;
  546.     if ( event->what == keyDown || event->what == autoKey )
  547.     {
  548.         result = kODTrue;
  549.         char key = event->message & charCodeMask;
  550.         ODBoolean cmdKeyDown = (event->modifiers & cmdKey) != 0;
  551.         ODBoolean optionKeyDown = (event->modifiers & optionKey) != 0;
  552.         switch ( key )
  553.         {
  554.             case kUpArrowKey:
  555.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODHomeArrowItem :
  556.                         kODPageUpArrowItem : kODUpArrowItem;
  557.                 break;
  558.             case kDownArrowKey:
  559.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODEndArrowItem :
  560.                         kODPageDownArrowItem : kODDownArrowItem;
  561.                 break;
  562.  
  563.             case kPageUpKey:
  564.                 *itemHit = kODPageUpArrowItem;
  565.                 break;
  566.             case kPageDownKey:
  567.                 *itemHit = kODPageDownArrowItem;
  568.                 break;
  569.             case kHomeKey:
  570.                 *itemHit = kODHomeArrowItem;
  571.                 break;
  572.             case kEndKey:
  573.                 *itemHit = kODEndArrowItem;
  574.                 break;
  575.  
  576.             default:
  577.                 result = kODFalse;
  578.         }
  579.     }
  580.     else
  581.         result = kODFalse;
  582.     return result || ODButtonKeyFilterProc( dlg, event, itemHit );
  583. }
  584.  
  585.  
  586. ModalFilterUPP
  587. GetODArrowKeyFilterProc( )
  588. {
  589.     if( !sArrowKeyFilter )
  590.         sArrowKeyFilter = NewModalFilterProc(&ODArrowKeyFilterProc);
  591.     return sArrowKeyFilter;
  592. }
  593.  
  594. // DMc: this debugging code disables use of enter to mean 'OK' when this var is set:
  595. // #if ODDebug
  596. // int gODButtonKeyNoEnterOkay = 0; // set to non-zero to disable enter for okay
  597. // #endif
  598.  
  599. pascal Boolean
  600. ODButtonKeyFilterProc(DialogPtr dialog, EventRecord *event, short *itemHit)
  601. {    
  602.     Rect            itemRect;
  603.     short            itemType;
  604.     Handle            itemHandle;
  605.     short            myItemHit = 0;
  606.  
  607.     const short        kEscKeyCode = 0x35;    // Virtual key code for the escape key
  608.  
  609.     if ( event->what == keyDown )
  610.     {
  611.         char key = event->message & charCodeMask;
  612.         switch ( key )
  613.         {
  614.             case kReturnKey:
  615.             case kEnterKey:
  616.                 GetDialogItem(dialog, kOKButton, &itemType, &itemHandle, &itemRect);
  617.                 ASSERT_CONTROL_ITEM(itemType);
  618.  
  619. // DMc: this debugging code disables use of enter to mean 'OK' when a var is set:
  620. // #if ODDebug
  621. //                 if ( !gODButtonKeyNoEnterOkay || key != kEnterKey )
  622. //                 {
  623. //                     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  624. //                         myItemHit = kOKButton;
  625. //                 }
  626. // #else
  627.                 if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  628.                     myItemHit = kOKButton;
  629. // #endif /*ODDebug*/
  630.                     
  631.                 break;
  632.             
  633.             case kEscapeKey:
  634.                 // Ensure that the escape key, not the clear key, was pressed
  635.                 if ( (event->message & keyCodeMask) == (kEscKeyCode << 8) )
  636.                 {
  637.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  638.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  639.                         myItemHit = kCancelButton;
  640.                 }
  641.                 break;
  642.  
  643.             case '.':        // cmd-period means cancel
  644.                 if ( event->modifiers & cmdKey )
  645.                 {
  646.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  647.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  648.                         myItemHit = kCancelButton;
  649.                 }
  650.                 break;
  651.  
  652.             default:
  653.                 if ( (sCmdKeyStrResID != 0)  && (event->modifiers & cmdKey) )
  654.                 {
  655.                     // Attempt to match the key to a key found in the STR# resource
  656.                     Handle stringsHandle = GetResource( 'STR#', sCmdKeyStrResID );
  657.                     if ( stringsHandle )
  658.                     {
  659.                         short     i;
  660.                         short    numStrings = **(short**)stringsHandle;
  661.                         Str255    cmdKeyCode;
  662.                         for ( i = 1; i <= numStrings; ++i )
  663.                         {
  664.                           GetIndString( cmdKeyCode, sCmdKeyStrResID, i );
  665.                           if ( cmdKeyCode[0] && cmdKeyCode[1] == key )
  666.                           {
  667.                             GetDialogItem(dialog, i, &itemType, &itemHandle, &itemRect);
  668.                             ASSERT_CONTROL_ITEM(itemType);
  669.                             if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  670.                             {
  671.                               myItemHit = i;    // Cool--record the item number that is hit
  672.                               break;
  673.                             }
  674.                           }
  675.                         }
  676.                     } 
  677.                 }
  678.                 break;
  679.         }
  680.  
  681.         if ( myItemHit != 0 )    // need to hilite a button
  682.         {
  683.             FlashButtonItem( dialog, myItemHit );
  684.             *itemHit = myItemHit;
  685.             return kODTrue;
  686.         }
  687.     
  688.     }
  689.     else if ( event->what == activateEvt )
  690.     {
  691.         Boolean isActivate = ((event->modifiers & activeFlag) != 0 );
  692.         ActivateAllControls(dialog, isActivate);
  693.     }
  694.  
  695.     // we only get here if we'd otherwise be returning false; all successes
  696.     // exit at "return kODTrue" above
  697.     return ODDialogFilterProc(dialog,event,itemHit);
  698. }
  699.  
  700.  
  701. ModalFilterUPP
  702. GetODButtonKeyFilterProc( )
  703. {
  704.     if( !sButtonKeyFilter )
  705.         sButtonKeyFilter = NewModalFilterProc(&ODButtonKeyFilterProc);
  706.     return sButtonKeyFilter;
  707. }
  708.  
  709.  
  710. void
  711. ODUseCommandKeyStringsResource( short resID )
  712. {
  713.     sCmdKeyStrResID = resID;
  714. }
  715.  
  716.  
  717. //==============================================================================
  718. // Updating the Menu Bar
  719. //==============================================================================
  720.  
  721. void ODDialogBegin( Environment* ev, ODSession* session, 
  722.             ODMenuBar* currentMenuBar, DialogPtr dialog )
  723. {
  724.     ODUnused(dialog);    // Later on, we can use this to support movable modals
  725.     
  726.     if ( sEv == kODNULL )
  727.         sEv = ev;
  728.  
  729.     if ( sSession == kODNULL )
  730.         sSession = session;
  731.  
  732.     ASSERT(currentMenuBar!=kODNULL,kODErrIllegalNullInput);
  733.     ASSERT(sSession!=kODNULL,kODErrIllegalNullInput);
  734.     
  735.     // Cleanup if needed
  736.     if ( sDialogInfo )
  737.         ODDisposePtr(sDialogInfo);
  738.  
  739.     // Allocate a new menu info record
  740.     sDialogInfo = (DialogBoxInfo*)ODNewPtrClear(sizeof(DialogBoxInfo),kDefaultHeapID);
  741.  
  742.     if ( sDialogInfo )
  743.     {
  744.         ODMenuID        editMenuID = 0;
  745.         ODPlatformMenu    editMenu = kODNULL;
  746.         short            redoItem;
  747.  
  748.         // Delete the Redo menu item so ModalDialog will handle the Edit menu right.
  749.         if ( currentMenuBar->IsCommandRegistered( sEv, kODCommandRedo ) )
  750.         {
  751.             currentMenuBar->GetMenuAndItem(sEv, kODCommandRedo, &editMenuID, &redoItem);
  752.             editMenu = currentMenuBar->GetMenu(sEv, editMenuID );
  753.         }
  754.         if ( editMenu )
  755.             SaveAndDeleteMenuItem(editMenu, redoItem, &sDialogInfo->redo);
  756.         else
  757.         {
  758.             ODDisposePtr(sDialogInfo);
  759.             sDialogInfo = kODNULL;
  760.         }
  761.     }
  762.     
  763.     // Lastly, export the OD clipboard in case the user pastes into the dialog
  764.     ODPlatformTypeList* types = session->GetStorageSystem(ev)->CreatePlatformTypeList(ev, kODNULL);
  765.     types->AddLast(sEv, 'TEXT');
  766.     types->AddLast(sEv, 'PICT');
  767.     sSession->GetClipboard(sEv)->SetPlatformClipboard(sEv, types);
  768.     ODDeleteObject(types);
  769. }
  770.  
  771.  
  772. void ODDialogEnd()
  773. {
  774.     // Restore the Redo menu item deleted by DialogBegin
  775.     if ( sDialogInfo )
  776.     {
  777.         RestoreMenuItem(&sDialogInfo->redo);
  778.         ODDisposePtr(sDialogInfo);
  779.         sDialogInfo = kODNULL;        // Don't allow to be called again
  780.     }
  781. }
  782.  
  783.  
  784. void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem )
  785. {
  786.     savedItem->menu = menu;
  787.     savedItem->item = item;
  788.     GetMenuItemText(menu, item, savedItem->text);
  789.     GetItemCmd(menu, item, &savedItem->cmdChar);
  790.     GetItemIcon(menu, item, &savedItem->iconID);
  791.     GetItemMark(menu, item, &savedItem->markChar);
  792.     GetItemStyle(menu, item, &savedItem->textStyle);
  793.     DeleteMenuItem(menu, item);
  794.     InvalMenuBar();
  795. }
  796.  
  797.  
  798. void RestoreMenuItem( MenuItemInfo *savedItem )
  799. {
  800.     InsertMenuItem(savedItem->menu, savedItem->text, savedItem->item -1);
  801.         // Still set item text in case of non-meta meta-characters.
  802.     SetMenuItemText(savedItem->menu, savedItem->item, savedItem->text);
  803.     SetItemCmd(savedItem->menu, savedItem->item, savedItem->cmdChar);
  804.     SetItemIcon(savedItem->menu, savedItem->item, savedItem->iconID);
  805.     SetItemMark(savedItem->menu, savedItem->item, savedItem->markChar);
  806.     SetItemStyle(savedItem->menu, savedItem->item, savedItem->textStyle);
  807.     InvalMenuBar();
  808. }
  809.  
  810.  
  811. pascal void
  812. ODOutlineDefaultButtonDrawProc(DialogPtr theDialog, short theItem)
  813. {
  814.     // NOTE: this proc only works on buttons whose DITL ID is 1.  theItem
  815.     // is unused, and so it doesn't matter whether the user item to which
  816.     // this proc is assigned (via SetDialogItem) has any geographical
  817.     // relation to the button.
  818.     
  819.     ODUnused(theItem);
  820.     Rect         itemRect;
  821.     Handle        itemHandle;
  822.     short        itemKind;
  823.  
  824.     WindowPtr    buttonWindow;
  825.     WindowPtr    savePort;
  826.     PenState    savePen;
  827.     short        buttonOval;
  828.     Boolean        isColorPort;
  829.  
  830.     const short kColorPort = 0xC000;
  831.  
  832.     GetDialogItem(theDialog, kOKButton, &itemKind, &itemHandle, &itemRect);
  833.     ASSERT_CONTROL_ITEM(itemKind);
  834.  
  835.     GetPort(&savePort);
  836.     buttonWindow = (**(ControlHandle)itemHandle).contrlOwner;
  837.     SetPort(buttonWindow);
  838.     GetPenState(&savePen);
  839.     PenNormal();
  840.  
  841.     InsetRect(&itemRect, -4, -4);
  842.     FrameRoundRect(&itemRect, 16, 16);
  843.     buttonOval = ((itemRect.bottom - itemRect.top)/2)+2;
  844.  
  845.     isColorPort = ((((CGrafPtr)buttonWindow)->portVersion & kColorPort) == kColorPort);
  846.     
  847.     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlInactive )
  848.     {
  849.         // Button is inactive, so outline with gray
  850.  
  851.         RGBColor    fgSaveColor;
  852.         RGBColor    fgNewColor;
  853.         RGBColor    bgColor;
  854.         Boolean        newGray = false;
  855.  
  856.         if ( isColorPort )
  857.         {
  858.             GetBackColor(&bgColor);
  859.             GetForeColor(&fgSaveColor);
  860.             fgNewColor = fgSaveColor;
  861.             
  862.             Rect globalRect = itemRect;
  863.             LocalToGlobal((Point *)&(globalRect.top));
  864.             LocalToGlobal((Point *)&(globalRect.bottom));
  865.             GDHandle targetDevice = GetMaxDevice(&globalRect);
  866.             
  867.             newGray = GetGray(targetDevice, &bgColor, &fgNewColor);
  868.         }
  869.  
  870.         if ( newGray )
  871.             RGBForeColor(&fgNewColor);
  872.         else
  873. #ifdef THINK_CPLUS
  874.             PenPat(ODQDGlobals.gray);
  875. #else
  876.             PenPat(&ODQDGlobals.gray);
  877. #endif
  878.  
  879.         PenSize(3, 3);
  880.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  881.         
  882.         if ( isColorPort )
  883.             RGBForeColor(&fgSaveColor);
  884.     }
  885.     else
  886.     {
  887.         // Button is active, so outline with black
  888. #ifdef THINK_CPLUS
  889.         PenPat(ODQDGlobals.black);
  890. #else
  891.         PenPat(&ODQDGlobals.black);
  892. #endif
  893.         PenSize(3, 3);
  894.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  895.     }
  896.  
  897.     SetPenState(&savePen);
  898.     SetPort(savePort);
  899. }
  900.  
  901.  
  902. UserItemUPP
  903. GetODOutlineDefaultButtonDrawProc( )
  904. {
  905.     if( !sOutlineDrawProc )
  906.         sOutlineDrawProc = NewUserItemProc(&ODOutlineDefaultButtonDrawProc);
  907.     return sOutlineDrawProc;
  908. }
  909.  
  910.  
  911. void
  912. ODUseDialogScriptData( DialogScriptData* dsd, DialogPtr dialog )
  913. {
  914.     sDlogScriptData = dsd;
  915.     dsd->SetDialog( dialog );
  916. }
  917.  
  918. pascal ODBoolean CheckKeyScriptChangeFilterProc( DialogPtr dialog,
  919.         EventRecord *event, short *itemHit)
  920. {
  921.     TEHandle teh = ((DialogPeek)dialog)->textH;
  922.     DialogScriptData* dsd = sDlogScriptData;
  923.     WASSERT( dsd );
  924.  
  925.     if ( dsd->Script() == ksmUninited )
  926.         dsd->SetScriptAndLockKeyboard();
  927.  
  928.     if ( event->what == keyDown )
  929.     {
  930.         if ( !dsd->ScriptChanged() )
  931.         {
  932.             ODScriptCode newScript = GetScriptManagerVariable(smKeyScript);
  933.             ODScriptCode fontScript = FontToScript((*teh)->txFont);
  934.             WASSERT( fontScript == dsd->Script() );
  935.             if ( fontScript != newScript )
  936.             {
  937.                 short newFont = GetScriptVariable( newScript, smScriptAppFond );
  938.                 (*teh)->txFont = newFont;
  939. //                TextFont(newFont);
  940.  
  941.                 dsd->SetScriptAndLockKeyboard( FontToScript(newFont) );
  942.             }
  943.         }
  944.     }
  945.  
  946.     // if this is the first time in this edit item, redraw in case
  947.     // we've switched fonts/scripts.
  948.     short currentItem = ((DialogPeek)dialog)->editField;
  949.     if ( dsd->ScriptChanged() && !dsd->ItemRedrawn(currentItem) )
  950.     {
  951.         dsd->SetRedrawn(currentItem);
  952.         short itemKind;
  953.         Handle ignoreH;
  954.         Rect ignoreR;
  955.         GetDialogItem( dialog, currentItem+1, &itemKind, &ignoreH, &ignoreR );
  956.         if ( itemKind == editText )
  957.         {
  958.             TECalText( teh );
  959.             Rect viewRect = (*teh)->viewRect;
  960.             TEUpdate( &viewRect, teh );
  961.         }
  962.     }
  963.  
  964.     // pass to the next filter proc.  This one just changes state, never
  965.     // consuming the event.
  966.     return kODFalse;
  967. }
  968.  
  969. void EnableOkButton(DialogPtr dlog, ODBoolean enable)
  970. {
  971.     Environment*    ev = somGetGlobalEnvironment();
  972.     short            itemType;
  973.     Handle            itemHandle;
  974.     Rect            itemRect;
  975.     ODBoolean        okEnabled;
  976.  
  977.     const short kButtonFrameInset = -4;
  978.  
  979.     GetDialogItem(dlog, kOKButton, &itemType, &itemHandle, &itemRect);    
  980.     ASSERT_CONTROL_ITEM(itemType);
  981.     okEnabled = (**(ControlHandle)itemHandle).contrlHilite == kControlActive;
  982.  
  983.     // there's nothing to do if the button is as it should be already
  984.     if ( enable != okEnabled )
  985.     {
  986.         HiliteControl((ControlHandle)itemHandle, enable ? kControlActive : kControlInactive);
  987.  
  988.         // Invalidate the default button frame so it will be redrawn dim
  989.         WindowPtr savePort;
  990.         GetPort(&savePort);
  991.         SetPort(dlog);
  992.         InsetRect(&itemRect, kButtonFrameInset, kButtonFrameInset);
  993.         InvalRect(&itemRect);
  994.         SetPort(savePort);
  995.     }
  996.     ActivateControl(dlog, kOKButton, enable); // put state into the control ref
  997. }
  998.  
  999. //    DrawGrayBox draws a gray box to be used as a separator.
  1000. //    On a ColorQD machine, a true-gray line is attempted.
  1001. //  On a B&W machine, a 50% pattern is used.
  1002.  
  1003. static pascal void DrawGrayBox(Rect *theBox)
  1004. {
  1005.     PenState    penState;
  1006.     GetPenState(&penState);
  1007.  
  1008.     PixPatHandle ppat = kODNULL;
  1009.     
  1010.     /* check if Color QuickDraw is available */    
  1011.     long response;
  1012.     if( Gestalt(gestaltQuickdrawFeatures, &response)==noErr
  1013.                 && BitTst(&response, 31-gestaltHasColor) ) {
  1014.         const RGBColor gray = {0x7FFF,0x7FFF,0x7FFF};
  1015.         ppat = NewPixPat();
  1016.         if( ppat )
  1017.             MakeRGBPat(ppat,&gray);
  1018.     }
  1019.  
  1020.     if( ppat )
  1021.         PenPixPat(ppat);
  1022.     else
  1023.         PenPat(&ODQDGlobals.gray);
  1024.         
  1025.     FrameRect(theBox);
  1026.     
  1027.     SetPenState(&penState);
  1028.  
  1029.     if( ppat )
  1030.         DisposePixPat(ppat);
  1031. }
  1032.  
  1033. pascal void DrawGrayBoxItem(DialogPtr theDialog, short theItem)
  1034. {
  1035.     Rect     boxRect;
  1036.     Handle    scratchHandle;
  1037.     short    scratchKind;
  1038.     
  1039.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &boxRect);
  1040.     DrawGrayBox(&boxRect);
  1041. }
  1042.  
  1043. pascal void DrawItemFrame(DialogPtr theDialog, short theItem)
  1044. {
  1045.     Rect     frameRect;
  1046.     Handle    scratchHandle;
  1047.     short    scratchKind;
  1048.     
  1049.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &frameRect);
  1050.     FrameRect(&frameRect);
  1051. }
  1052.  
  1053. ////////////////////////////////////////////////////////////////////////////////
  1054. // DrawITextInDlogBox
  1055. // Given a dialog, a rect and an ODIText*, truncate the text to fit in the
  1056. // rect and then draw it in the dialog.  Return result telling whether any
  1057. // change was made.
  1058. ////////////////////////////////////////////////////////////////////////////////
  1059.  
  1060. ODBoolean DrawITextInDlogBox( ODIText* itext, const Rect* textRect,
  1061.         DialogPtr dlog, ODBoolean tryToTruncate )
  1062. {
  1063.     WASSERT(dlog);
  1064.     WindowPtr savePort;
  1065.     GetPort(&savePort);
  1066.     SetPort(dlog);
  1067.  
  1068.     PenState savedPenState;
  1069.     GetPenState(&savedPenState);
  1070.     PenNormal();
  1071.  
  1072.     short saveFont = dlog->txFont;
  1073.     short savedTextMode = dlog->txMode;
  1074.     
  1075.     ODScriptCode scriptCode = GetITextScriptCode(itext);
  1076.     if ( scriptCode != FontToScript(saveFont) )
  1077.         TextFont(GetScriptVariable(scriptCode,smScriptAppFond));
  1078.     
  1079.     char buffer[256];
  1080.     ODSShort len = GetITextStringLength(itext);
  1081.     if ( len > 255 ) len = 255;
  1082.     ODBlockMove( GetITextPtr( itext ), buffer, len );
  1083.     short truncResult;
  1084.     if ( tryToTruncate )
  1085.         truncResult = TruncText( textRect->right - textRect->left - 1,
  1086.             buffer, &len, truncEnd);
  1087.     TETextBox( buffer, len,    textRect, teFlushDefault );
  1088.  
  1089.     TextFont(saveFont);
  1090.     TextMode(savedTextMode);
  1091.     SetPenState(&savedPenState);
  1092.     SetPort(savePort);
  1093.     return tryToTruncate? truncResult == 1 : kODFalse;    // 1 means truncation needed and successful
  1094. }
  1095.  
  1096. ////////////////////////////////////////////////////////////////////////////////
  1097. // FlashButtonItem
  1098. // Given a dialog and an item representing a button, flash that button,
  1099. // highlighting it for 8 ticks and then reverting.
  1100. ////////////////////////////////////////////////////////////////////////////////
  1101. void FlashButtonItem( DialogPtr dialog, short itemHit )
  1102. {
  1103.     Rect itemRect;
  1104.     short itemType;
  1105.     Handle itemHandle;
  1106.  
  1107.     GetDialogItem( dialog, itemHit, &itemType, &itemHandle, &itemRect);
  1108.     ASSERT_CONTROL_ITEM(itemType);
  1109.     HiliteControl((ControlHandle)itemHandle, kControlButtonPart);
  1110.     unsigned long ticks = TickCount() + 8;
  1111.     while ( TickCount() < ticks ) ;
  1112.     HiliteControl((ControlHandle)itemHandle, kControlActive);    // Turn off hilite
  1113. }
  1114.  
  1115. ////////////////////////////////////////////////////////////////////////////////
  1116. // ArrowKeyScrollList
  1117. // Given an "item" representing an up or down arrow or any of the other keys
  1118. // recognized by ODArrowKeyFilterProc above, a ListHandle indicating the list
  1119. // in which scrolling is taking place, pageSize giving the number of entries to
  1120. // be skipped by a "page down" command, and the zero-based index of the last
  1121. // entry in the list, do the right thing for the key selected.  So far this
  1122. // routine is used for lists embedded in dialogs, and it's up to the caller
  1123. // to determine which list is meant if there is more than one.
  1124. // NOTE that nothing happens currently if no list item is selected.  There needs
  1125. // to be a starting point for scrolling.
  1126. ////////////////////////////////////////////////////////////////////////////////
  1127.  
  1128. void ArrowKeyScrollList( ODSShort arrowItem, ListHandle listH,
  1129.         ODSShort pageSize, ODSShort lastEntry )
  1130. {
  1131.     ODSShort limitCell;
  1132.     ODSShort delta;
  1133.     switch( arrowItem )
  1134.     {
  1135.         case kODUpArrowItem:
  1136.             limitCell = 0;
  1137.             delta = -1;
  1138.             break;
  1139.  
  1140.         case kODDownArrowItem:
  1141.             limitCell = lastEntry;
  1142.             delta = 1;
  1143.             break;
  1144.  
  1145.         case kODPageUpArrowItem:
  1146.             limitCell = 0;
  1147.             delta = 0 - pageSize;
  1148.             break;
  1149.  
  1150.         case kODPageDownArrowItem:
  1151.             limitCell = lastEntry;
  1152.             delta = pageSize;
  1153.             break;
  1154.  
  1155.         case kODHomeArrowItem:
  1156.             limitCell = 0;
  1157.             delta = 0 - lastEntry;
  1158.             break;
  1159.  
  1160.         case kODEndArrowItem:
  1161.             limitCell = lastEntry;
  1162.             delta = lastEntry;
  1163.             break;
  1164.  
  1165.         default:
  1166.             WARN( "unknown arrow key/item" );
  1167.             return;
  1168.     }
  1169.  
  1170.     Cell selectedCell = {0,0};
  1171.     if ( !LGetSelect( true, &selectedCell, listH ) 
  1172.             || (selectedCell.v == limitCell) ) 
  1173.         return;
  1174.     LSetSelect( false, selectedCell, listH );
  1175.     selectedCell.v += delta;
  1176.     if ( selectedCell.v < 0 )
  1177.         selectedCell.v = 0;
  1178.     else if ( limitCell > 0 && selectedCell.v > limitCell )
  1179.         selectedCell.v = limitCell;
  1180.     LSetSelect( true, selectedCell, listH );
  1181.     LAutoScroll(listH);
  1182. }
  1183.  
  1184. //------------------------------------------------------------------------------
  1185. // ReplaceIntoString
  1186. //------------------------------------------------------------------------------
  1187. // Substitutes str0 for all occurances of "^0", and str1 for "^1", in the string
  1188. // retrieved from the 'STR ' resource identified by the first parameter.  Either
  1189. // str0 or str1 may be null.  Uses the current resource chain to find the 'STR '
  1190. // resource.
  1191.  
  1192. void ReplaceIntoString(ODSShort strResourceID,
  1193.                         ConstStr255Param str0,
  1194.                         ConstStr255Param str1,
  1195.                         Str255 destString)
  1196. {
  1197.     StringHandle msgHandle = GetString(strResourceID);
  1198.     if ( msgHandle )
  1199.     {
  1200.         DetachResource((Handle) msgHandle);
  1201.  
  1202.         ODHandle textHandle;
  1203.  
  1204.         HLock((Handle) msgHandle);
  1205.         ODHandle templateText = PStrToText(*msgHandle);
  1206.         HUnlock((Handle) msgHandle);
  1207.  
  1208.         if ( str0 )
  1209.         {
  1210.             textHandle = PStrToText(str0);
  1211.             if ( textHandle )
  1212.             {
  1213.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^0");
  1214.                 ODDisposeHandle(textHandle);
  1215.             }
  1216.         }
  1217.         
  1218.         if ( str1 )
  1219.         {
  1220.             textHandle = PStrToText(str1);
  1221.             if ( textHandle )
  1222.             {
  1223.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^1");
  1224.                 ODDisposeHandle(textHandle);
  1225.             }
  1226.         }
  1227.  
  1228.         TextToPStr(templateText, destString);
  1229.  
  1230.         ODDisposeHandle(templateText);
  1231.         DisposeHandle((Handle) msgHandle);
  1232.     }
  1233.     else
  1234.         if( ResError() != memFullErr )
  1235.         {
  1236.             WARN("ReplaceIntoString didn't find STR %hd",strResourceID);
  1237.             destString[0] = 0;
  1238.         }
  1239. }
  1240.  
  1241.  
  1242. //------------------------------------------------------------------------------
  1243. // LookupString
  1244. //
  1245. // Searches a MacApp-style 'errs' table for a value, then looks up the
  1246. // associated string from the associated 'STR#' resource.
  1247. //------------------------------------------------------------------------------
  1248. ODBoolean LookupString(ODError value,
  1249.                        short resourceID,
  1250.                        Str255 str)
  1251. {
  1252.     struct ErrRecord
  1253.     {
  1254.         ODError lowErr, highErr;
  1255.         ODULong index;
  1256.     };
  1257.  
  1258.     typedef ErrRecord* ErrRecordPointer;
  1259.     typedef ErrRecordPointer* ErrRecordHandle;
  1260.  
  1261.     CUsingLibraryResources r;
  1262.  
  1263.     str[0] = 0;
  1264.     ErrRecordHandle table = (ErrRecordHandle)GetResource('errs', resourceID);
  1265.     
  1266.     if (table)
  1267.     {
  1268.         short lenTab;
  1269.         short strID = 0;
  1270.         
  1271.         ErrRecordPointer pEntry = *table;    // careful, pointing into unlocked resource...
  1272.  
  1273.         lenTab = (short)(GetHandleSize((Handle)table) / sizeof(ErrRecord));
  1274.         for (short i = 1; i <= lenTab; ++i, ++pEntry)
  1275.         {
  1276.             if (pEntry->lowErr == 0)
  1277.                 strID = (short)(pEntry->index);
  1278.             else if ((pEntry->lowErr <= value) && (value <= pEntry->highErr))
  1279.             {
  1280.                 if (pEntry->index > 0)
  1281.                 {
  1282.                     GetIndString(str, strID, (short)(pEntry->index));
  1283.                 }
  1284.                 return kODTrue;
  1285.             }
  1286.         }
  1287.     }
  1288.     return kODFalse;
  1289. } // SearchErrTable 
  1290.  
  1291.  
  1292.  
  1293. //--------------------------------------------------------------------
  1294. // GetODITextInd
  1295. // Gets string # (index) from the 'STR#' resource given by resID 
  1296. // into an IText* whose script and language codes are those of 
  1297. // the current system script.
  1298. //--------------------------------------------------------------------
  1299.  
  1300. ODIText* GetODITextInd(short resID, short index)
  1301. {
  1302.     Str255 pStr = "\p";
  1303.     GetIndString(pStr, resID, index);
  1304.     ODScriptCode script = FontToScript( GetSysFont() );
  1305.     return CreateITextPString(script,
  1306.                             GetScriptVariable(script, smScriptLang), 
  1307.                             pStr);
  1308. }
  1309.  
  1310.  
  1311. //--------------------------------------------------------------------
  1312. // GetODIText
  1313. // Turns an 'STR ' resource of the given resID into an ODIText* whose
  1314. // language and script codes are those of the current system script.
  1315. //--------------------------------------------------------------------
  1316.  
  1317. ODIText* GetODIText(short resID)
  1318. {
  1319.     Handle textHandle;
  1320.     ODIText* iText = kODNULL;
  1321.     
  1322.     textHandle = (Handle)GetString(resID);
  1323.     
  1324.     if ( textHandle != kODNULL )
  1325.     {
  1326.         // CreateIText copies the values passed into it, so we don't
  1327.         // have to worry about the resource handle moving outside of
  1328.         // the scope of this function.
  1329.  
  1330.         ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1331.         ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1332.         HLock(textHandle);
  1333.         iText = CreateIText( script, lang, (StringPtr)*textHandle );
  1334.             
  1335.         ReleaseResource(textHandle);
  1336.     }
  1337.     
  1338.     return iText;
  1339. }
  1340.  
  1341. //------------------------------------------------------------------------------
  1342. // SetDialogTextStyle
  1343. //------------------------------------------------------------------------------
  1344.  
  1345. void SetDialogTextStyle(DialogPtr dlg, short finfResourceID,
  1346.         ODScriptCode script)
  1347. {
  1348. #if PRAGMA_ALIGN_SUPPORTED
  1349. #pragma options align=mac68k
  1350. #endif
  1351.  
  1352.     typedef struct {
  1353.         short count;
  1354.         short fontNumber;
  1355.         short fontStyl;
  1356.         short fontSize;
  1357.     } FontSpec;
  1358.  
  1359. #if PRAGMA_ALIGN_SUPPORTED
  1360. #pragma options align=reset
  1361. #endif
  1362.  
  1363.     typedef FontSpec** FontSpecHandle;
  1364.     FontInfo    finfo;
  1365.     
  1366.     FontSpecHandle finfHandle = (FontSpecHandle) GetResource('finf', finfResourceID);
  1367.  
  1368.     if ( finfHandle )
  1369.     {
  1370.         SetPort(dlg);
  1371.         
  1372.         short font;
  1373.         if ( script != smCurrentScript )
  1374.             font = GetScriptVariable( script, smScriptAppFond );    // <eeh> smScriptSysFond better?
  1375.         else
  1376.             font = (**finfHandle).fontNumber;
  1377.         
  1378.         TextFont(font);
  1379.         TextFace((**finfHandle).fontStyl);
  1380.         TextSize((**finfHandle).fontSize);
  1381.         TEHandle te = ((DialogPeek)dlg)->textH;
  1382.         (**te).txFont = font;
  1383.         (**te).txSize = (**finfHandle).fontSize;
  1384.         (**te).txFace = (**finfHandle).fontStyl;
  1385.         GetFontInfo(&finfo);
  1386.         (**te).lineHeight = finfo.leading + finfo.ascent + finfo.descent;
  1387.         (**te).fontAscent = finfo.ascent;
  1388.         TECalText(te);
  1389.         ReleaseResource((Handle) finfHandle);
  1390.     } else
  1391.         if( ResError() != memFullErr )
  1392.             WARN("SetDialogTextStyle didn't find 'finf' %hd",finfResourceID);
  1393. }
  1394.  
  1395. //-------------------------------------------------------------------------------------
  1396. // SetPopupItemScript
  1397. //-------------------------------------------------------------------------------------
  1398. // "scriptID" should be a true script code, not an implicit script code
  1399. //
  1400. // This routine assumes the popup is drawn using the font of the current port.
  1401. //
  1402. // Setting the script of a popup menu item has two bad consequences:
  1403. // The title and item appear in bold face, and the width of the
  1404. // menu is increased.  This is true even if the script specified
  1405. // is the same as the default script!  So only specify a script if its different.
  1406.  
  1407. void SetPopupItemScript(MenuHandle menu, short itemNum, short scriptID)
  1408. {
  1409.     const ODSShort kUseSpecificScript = 0x1c;
  1410.  
  1411.     ODSLong    savedSMFontForceFlag = GetScriptManagerVariable(smFontForce);
  1412.     SetScriptManagerVariable(smFontForce, false);
  1413.  
  1414.     // Since the popup is drawn using the window font, compare the argument
  1415.     // script to the script of the current graphics port.
  1416.     GrafPtr curPort;
  1417.     GetPort(&curPort);
  1418.  
  1419.     if ( scriptID == smSystemScript )
  1420.         scriptID = (short) GetScriptManagerVariable(smSysScript);
  1421.  
  1422.     if ( scriptID != FontToScript(curPort->txFont) )
  1423.     {
  1424.         SetItemCmd(menu, itemNum, kUseSpecificScript);
  1425.         SetItemIcon(menu, itemNum, scriptID);
  1426.     }
  1427.     
  1428.     SetScriptManagerVariable(smFontForce, savedSMFontForceFlag);
  1429. }
  1430.  
  1431.  
  1432. //-------------------------------------------------------------------------------------
  1433. // Implementation of DialogScriptData class
  1434. //-------------------------------------------------------------------------------------
  1435.  
  1436. DialogScriptData::DialogScriptData()
  1437. {
  1438.     fItemRedrawn = 0L;
  1439.     fMustUnlock = kODFalse;
  1440.     fScript = ksmUninited;
  1441. }
  1442.  
  1443. DialogScriptData::~DialogScriptData()
  1444. {
  1445.     if ( fMustUnlock )
  1446.         this->ReleaseLockout();
  1447. }
  1448.  
  1449. void DialogScriptData::SetScriptAndLockKeyboard()
  1450. {
  1451. //    this->SetScriptAndLockKeyboard( FontToScript( GetAppFont() ) );
  1452.     WASSERT( FontToScript( GetSysFont()) == FontToScript( GetAppFont() ));
  1453.     this->SetScriptAndLockKeyboard( FontToScript( GetSysFont() ) );
  1454. }
  1455.  
  1456. // There are two cases we need to be aware of here when the script passed
  1457. // in comes from an existing IText* and isn't Roman.  First, it's possible
  1458. // that the keyscript is not yet set to that script (that it's still Roman).
  1459. // Second, the dialog may not be in a state to properly display that text.
  1460.  
  1461. void DialogScriptData::SetScriptAndLockKeyboard( ODScriptCode script )
  1462. {
  1463.     if ( script != smRoman )    // lock all changes out: switch to Roman will
  1464.     {                            // result in non-Roman text being garbage
  1465.         if ( GetScriptManagerVariable(smKeyScript) != script )
  1466.             KeyScript( script );    // script may not yet have been set
  1467.  
  1468.         WASSERT(fDialog);
  1469.         TEHandle teh = ((DialogPeek)fDialog)->textH;
  1470.         if ( FontToScript( (*teh)->txFont ) != script )
  1471.         {
  1472.             (*teh)->txFont = GetScriptVariable( script, smScriptSysFond );            
  1473.         }
  1474.  
  1475. //        KeyScript( smKeyDisableKybdSwitch );    // <eeh> 1/6
  1476.         fMustUnlock = kODTrue;
  1477.     }
  1478.     fScript = script;
  1479. }
  1480.  
  1481. void DialogScriptData::ReleaseLockout()
  1482. {
  1483.     if ( fMustUnlock != kODFalse )
  1484.     {
  1485. //        KeyScript( smKeyEnableKybds );    // <eeh> 1/6
  1486.         fMustUnlock = kODFalse;
  1487.     }
  1488. }
  1489.  
  1490. ODBoolean DialogScriptData::ItemRedrawn( short item )
  1491. {
  1492.     WASSERT( item < kMaxNumItems );
  1493.     return (fItemRedrawn & 1L<<(item-1)) != 0;
  1494. }
  1495.  
  1496. void DialogScriptData::SetRedrawn( short item )
  1497. {
  1498.     WASSERT( item < kMaxNumItems );
  1499.     fItemRedrawn |= 1L<<(item-1);
  1500. }
  1501.